package com.proxy.scanandcheck.checker.http.proxy;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import com.proxy.scanandcheck.common.util.Constants;
import com.proxy.scanandcheck.common.valueobject.Proxy;

/**
 * Send a request via proxy.
 *
 */
public abstract class ClientExecuteProxy {
	
	private HttpHost proxy;
	private HttpGet httpGet;
	private HttpClient httpclient;
	private Proxy myProxy;
	
	public ClientExecuteProxy(HttpClient httpclient,Proxy myProxy,HttpGet httpGet)
	{
		this.httpclient = httpclient;
		this.myProxy = myProxy;
		this.proxy = new HttpHost(myProxy.getHostname(),myProxy.getPort(),myProxy.getSchemeName());
		this.httpGet = httpGet;
	}

	/**
	 * Check proxy if valid.
	 * @throws Exception
	 */
	public Document execue() throws Exception {
		
//		HttpGet req = new HttpGet("/");
//		HttpGet req = new HttpGet("/search?q=" + keyword);
		
		
		Document doc = null;
		try {
			System.setErr(null);
			httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
					this.proxy);
			//CONNECTION_TIMEOUT
			httpclient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, Constants.CONNECTION_TIMEOUT); 
			//SO_TIMEOUT
			httpclient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, Constants.READ_TIMEOUT);
			httpclient.getParams().setParameter("http.connection-manager.timeout", Constants.CONNECTION_MANAGER_TIMEOUT);
			
			httpclient.getParams().setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024);
			
//			HttpProtocolParams.setUserAgent(httpclient.getParams(),  
//	                "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");
//			((DefaultHttpClient)httpclient).setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(3, false));
			


			HttpResponse response = httpclient.execute(httpGet);
//			HttpResponse response = httpclient.execute(this.target, req);
			
			HttpEntity entity = response.getEntity();

			boolean statusResult = response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
			boolean result = statusResult;
			
			String responseContent = "";
			if (entity != null) {
				responseContent = EntityUtils.toString(entity,Consts.UTF_8);
				doc = Jsoup.parse(responseContent);
			}
			
			if(statusResult)
			{
//				System.out.println(doc);
				boolean checkGooglePattern = checkStringIfFollowPattern(responseContent,Constants.GOOGLE_REGEX_STRING);
				result = checkGooglePattern;
			}
			
			if(statusResult && checkHarmfulContent(responseContent))
			{
				result = false;
			}
			
			if(result)
			{
				System.out.println(this.proxy.toHostString() + this.getValidDisplayString());
				this.updateResultByValid(myProxy);
				myProxy.setDocument(doc);
			}
			else
			{
				doc = null;
//				System.out.println(this.proxy.toHostString() + this.getInvalidDisplayString());
			}
			
			
		} catch (Exception e) {
			e.printStackTrace();
//			System.out.println(this.proxy.toHostString() + this.getInvalidDisplayString());
			httpGet.abort();
			this.updateResultByInvalid(myProxy);
		} finally {
			httpGet.releaseConnection();
		}
		return doc;
	}
	
	protected static boolean checkStringIfFollowPattern(String candidate,String [] regexString)
	{
		candidate = candidate
				.replaceAll("\r", "")
				.replaceAll("\n", "")
				.replaceAll("\r\n", "");
		String regex = "";
		for (int i = 0; i < regexString.length; i++)
		{
			regex += ".*" + regexString[i] +".*" ;
			if(i != regexString.length -1)
			{
				regex += "|";
			}
		}
		Pattern pattern = Pattern.compile(regex);  
	    Matcher matcher = pattern.matcher(candidate);
		return matcher.matches();
	}
	
	/**
	 * Check the response content if it is harmful.
	 * @param candidate
	 * @return
	 */
	protected boolean checkHarmfulContent(String candidate)
	{
		String [] regexString = {
				"computer virus or spyware application",
				"entire network is affected",
				"http://www.download.com/Antivirus",
				"/images/yellow_warning.gif",
				"sending automated queries"};
	    
		return checkStringIfFollowPattern(candidate, regexString);
	}
	
	/**
	 * get valid display string which implement in sub class.
	 * @return
	 */
	public abstract String getValidDisplayString();
	
	/**
	 * get invalid display string which implement in sub class.
	 * @return
	 */
	public abstract String getInvalidDisplayString();
	
	/**
	 * update validForGoogleHost or validForOtherHost 
	 * to true for myProxy object, which implement in sub class.
	 * @param myProxy
	 */
	public abstract void updateResultByValid(Proxy myProxy);
	
	/**
	 * update validForGoogleHost or validForOtherHost 
	 * to false for myProxy object, which implement in sub class.
	 * @param myProxy
	 */
	public abstract void updateResultByInvalid(Proxy myProxy);
	
	/**
	 * check if the proxy is valid.
	 * @return
	 */
	
	public abstract String [] getRegexString();
	
	public  static void main(String args[])
	{
		String candidate = "<!doctype html><html itemscope=\"itemscope\" itemtype=\"http://schema.org/WebPage\"><head><meta itemprop=\"image\" content=\"/images/google_favicon_128.png\"><title>Google</title><script>";
		
		System.out.println(checkStringIfFollowPattern(candidate, Constants.GOOGLE_REGEX_STRING));
	}
	
}
